﻿using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Protocol;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using WPF_MQTT.Models;

namespace WPF_MQTT
{
    public class MainWindowViewModel : BindableBase
    {

        private IMqttClient mqttClient = null;

        public MainWindowViewModel()
        {
            ConnectCommand = new DelegateCommand(Connect);
            DisConnectCommand = new DelegateCommand(DisConnect);
            PublishCommand = new DelegateCommand(Publish);
            SubscribeCommand = new DelegateCommand(Subscribe);
            QosModels = QosModel.Init();
        }

        public string Title { set; get; } = "MQTT-CE-SHI";

        private string ip = "127.0.0.1";
        public string Ip
        {
            get { return ip; }
            set { SetProperty(ref ip, value); }
        }

        private int port = 1883;
        public string Port
        {
            get { return port.ToString(); }
            set
            {
                if (int.TryParse(value, out int cValue))
                    port = cValue;
                else
                    MessageBox.Show("端口类型转换失败！");
            }
        }

        private string username = "admin";
        public string UserName
        {
            get => username;
            set { SetProperty(ref username, value); }
        }

        private string password = "123";
        public string Password
        {
            get => password;
            set
            {
                SetProperty(ref password, value);
            }
        }

        private string publishTopic = "test";
        public string PublishTopic
        {
            get => publishTopic;
            set
            {
                SetProperty(ref publishTopic, value);
            }
        }

        private string subscribeTopic = "test";
        public string SubscribeTopic
        {
            get => subscribeTopic;
            set
            {
                SetProperty(ref subscribeTopic, value);
            }
        }

        private ObservableCollection<string> receiveMessages = new ObservableCollection<string>();
        public ObservableCollection<string> ReceiveMessages
        {
            get => receiveMessages;
            set
            {
                SetProperty(ref receiveMessages, value);
            }
        }

        private ObservableCollection<SystemLogModel> systemLogModels = new ObservableCollection<SystemLogModel>();
        public ObservableCollection<SystemLogModel> SystemLogModels
        {
            get => systemLogModels;
            set
            {
                SetProperty(ref systemLogModels, value);
            }
        }

        private string publishMessage = "input the message that you what  want to send";
        public string PublishMessage
        {
            get => publishMessage;
            set
            {
                SetProperty(ref publishMessage, value);
            }
        }

        public List<QosModel> QosModels { get; set; }

        public bool isRetain = true;
        public bool IsRetain
        {
            get => isRetain;
            set => SetProperty(ref isRetain, value);
        }

        public ICommand PublishCommand { private set; get; }
        private void Publish()
        {
            if (mqttClient != null && mqttClient.IsConnected)
            {
                var qos = QosModels.First(c => c.IsChecked).QoS;

                MqttApplicationMessage message = new MqttApplicationMessageBuilder()
                    .WithTopic(publishTopic)
                    .WithPayload(publishMessage)
                    .WithRetainFlag(IsRetain)
                    .WithQualityOfServiceLevel(qos)
                    //.WithUserProperty("username","mike")
                    .Build();

                mqttClient.PublishAsync(message).Wait();
                RecordLog($"主题{SubscribeTopic}发送数据成功！");
            }
            else
                RecordLog("mqtt连接尚未初始化！");
        }

        public ICommand ConnectCommand { private set; get; }
        private void Connect()
        {
            MqttClientOptions options = new MqttClientOptionsBuilder()
                .WithClientId(Title)
                .WithTcpServer(ip, port)
                .WithCredentials(username, password)
                .Build();

            mqttClient = new MqttFactory().CreateMqttClient();

            mqttClient.ConnectedAsync += Client_ConnectedAsync;
            mqttClient.DisconnectedAsync += Client_DisconnectedAsync;

            mqttClient.ConnectAsync(options).Wait();
        }

        public DelegateCommand SubscribeCommand { set; get; }
        private void Subscribe()
        {
            if (mqttClient != null && mqttClient.IsConnected)
            {
                mqttClient.SubscribeAsync(SubscribeTopic).Wait();
                mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
                RecordLog($"订阅主题{SubscribeTopic}成功！");
            }
            else
                RecordLog("mqtt连接尚未初始化！");
        }

        private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            var message = arg.ApplicationMessage.ConvertPayloadToString();
            if (!string.IsNullOrEmpty(message))
            {
                Application.Current.Dispatcher.Invoke(() =>
                {
                    ReceiveMessages.Add(message);
                });
                RecordLog($"主题{SubscribeTopic}接收数据成功！");
            }

            return Task.CompletedTask;
        }

        private Task Client_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
        {
            RecordLog("Broker断开连接成功！");
            return Task.CompletedTask;
        }

        private Task Client_ConnectedAsync(MqttClientConnectedEventArgs arg)
        {
            if (arg.ConnectResult.ResultCode == MqttClientConnectResultCode.Success)
            {
                RecordLog("Broker连接成功！");
            }
            else
            {
                RecordLog("Broker连接失败！");
            }
            return Task.CompletedTask;
        }

        public ICommand DisConnectCommand { private set; get; }
        private void DisConnect()
        {
            if (mqttClient.IsConnected)
            {
                mqttClient.DisconnectAsync().Wait();
            }
        }

        private void RecordLog(string message)
        {
            Application.Current.Dispatcher.BeginInvoke(() =>
            {
                SystemLogModels.Add(new SystemLogModel(message));
            });
        }
    }
}
